#include "recvfrom_msg.h"

ssize_t recvfrom_msg(int fd, void* ptr, size_t nbytes, int* flagsp, sockaddr* sa, socklen_t* salen,
		struct in_pktinfo *pktp)
{
  struct msghdr msg;
  struct iovec iov[1];
  ssize_t n;

  struct cmsghdr* cmptr;
  union {
	  struct cmsghdr cm;
	  char control[CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct unp_in_pktinfo))];
  } control_un;

  memset(&msg,0,sizeof(msg));
  iov[0].iov_base = ptr;
  iov[0].iov_len = nbytes;
  msg.msg_control = control_un.control;
  msg.msg_controllen = sizeof(control_un.control);
  msg.msg_flags = 0 ;
  msg.msg_name = sa;
  msg.msg_namelen = *salen;
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;

  n = recvmsg(fd,&msg,*flagsp);
  if ( n < 0)
    return n;

  *salen = msg.msg_namelen;
  if (pktp)
    memset(pktp,0,sizeof(in_pktinfo));

  *flagsp = msg.msg_flags;
  if (msg.msg_controllen < sizeof(cmsghdr) || (msg.msg_flags & MSG_TRUNC) || pktp == NULL)
    return n;

  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = CMSG_NXTHDR(&msg,cmptr))
  {
#ifdef  IP_PKTINFO
    if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
    {
      struct in_pktinfo *in = (struct in_pktinfo*)CMSG_DATA(cmptr);
      memcpy(pktp, in, sizeof(struct in_pktinfo));
      continue;
    }
#endif
  }

  return n;
}

